﻿#region 命名空间
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Microsoft.Xna.Framework.Content.Pipeline;
#endregion

namespace ContentFactory
{
    /// <summary>
    /// 提供素材导入/处理程序。
    /// </summary>
    public static class PipelineManager
    {
        #region 字段

        internal static Type[] PipelineTypes;
        internal static List<Type> SerializableTypes;

        static readonly Dictionary<Type, ContentImporterAttribute> importers;
        static readonly Dictionary<Type, ContentProcessorAttribute> processors;
        static readonly Dictionary<string, ContentImporterAttribute> defaultImporters;
        static readonly Dictionary<ContentImporterAttribute, ContentProcessorAttribute> defaultProcessors;
        static readonly Dictionary<string, bool> buildinFileNames;

        #endregion

        #region 初始化

        /// <summary>
        /// 初始化。
        /// </summary>
        static PipelineManager()
        {
            importers = new Dictionary<Type, ContentImporterAttribute>();
            processors = new Dictionary<Type, ContentProcessorAttribute>();
            defaultImporters = new Dictionary<string, ContentImporterAttribute>();
            defaultProcessors = new Dictionary<ContentImporterAttribute, ContentProcessorAttribute>();
            buildinFileNames = new Dictionary<string, bool>()
            {
                {"ContentFactory.exe", true},
                {"DW.SharpTools.dll", true},
                {"DW.WPFToolkit.dll", true},
                {"libmojoshader.dll", true},
                {"NAudio.dll", true},
                {"NAudio.WindowsMediaFormat.dll", true},
                {"PVRTexLibC.dll", true},
                {"SharpDX.D3DCompiler.dll", true},
                {"SharpDX.dll", true},
                {"Xceed.Wpf.Toolkit.dll", true},
                {"yeti.mmedia.dll", true},
                {"yeti.mp3.dll", true},
                {"MonoGameContentBuild.dll", true},                
                {"Microsoft.WindowsAPICodePack.dll", true},
                {"Microsoft.WindowsAPICodePack.Shell.dll", true},

                {"Microsoft.Xna.Framework.Content.Pipeline.AudioImporters.dll", false},
                {"Microsoft.Xna.Framework.Content.Pipeline.dll", false},
                {"Microsoft.Xna.Framework.Content.Pipeline.EffectImporter.dll", false},
                {"Microsoft.Xna.Framework.Content.Pipeline.FBXImporter.dll", false},
                {"Microsoft.Xna.Framework.Content.Pipeline.TextureImporter.dll", false},
                {"Microsoft.Xna.Framework.Content.Pipeline.VideoImporters.dll", false},
                {"Microsoft.Xna.Framework.Content.Pipeline.XImporter.dll", false},
                {"MonoGameContentProcessors.dll", false},
            };
        }

        #endregion

        #region 方法

        /// <summary>
        /// 初始化所有素材导入/处理程序。
        /// </summary>
        public static void Initialize()
        {
            Type importerType = typeof(IContentImporter);
            Type processorType = typeof(IContentProcessor);

            SerializableTypes = new List<Type>();
            List<Type> pipelineTypes = new List<Type>();
            DirectoryInfo directory = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);
            foreach (var file in directory.GetFiles())
            {
                bool checkSerializable = true;
                if (buildinFileNames.ContainsKey(file.Name))
                {
                    if (buildinFileNames[file.Name])
                        continue;
                    else
                        checkSerializable = false;
                }
                string assemblyExtension = file.Extension.ToUpper();
                if (assemblyExtension == ".DLL" || assemblyExtension == ".EXE")
                {
                    // 加载 Dll 并跳过非 .Net Dll。
                    Assembly assembly = null;
                    try
                    {
                        assembly = Assembly.LoadFrom(file.FullName);
                    }
                    catch (Exception exception)
                    {
                    }
                    if (assembly == null) continue;
                    // 获取 Type 并忽略异常。
                    Type[] types = null;
                    try
                    {
                        types = assembly.GetTypes();
                    }
                    catch (ReflectionTypeLoadException exception)
                    {
                        types = exception.Types;
                    }
                    foreach (var type in types)
                    {
                        if (importerType.IsAssignableFrom(type))
                        {
                            foreach (var attribute in type.GetCustomAttributes(true))
                            {
                                if (attribute is ContentImporterAttribute)
                                {
                                    ContentImporterAttribute importerAttribute = attribute as ContentImporterAttribute;
                                    importers.Add(type, importerAttribute);
                                    if (type.IsPublic)
                                        pipelineTypes.Add(type);
                                    foreach (var fileExtension in importerAttribute.FileExtensions)
                                    {
                                        string extension = fileExtension.ToUpper();
                                        if (!defaultImporters.ContainsKey(extension))
                                        {
                                            defaultImporters.Add(extension, importerAttribute);
                                        }
                                    }
                                    break;
                                }
                            }
                        }
                        else if (processorType.IsAssignableFrom(type))
                        {
                            foreach (var attribute in type.GetCustomAttributes(true))
                            {
                                if (attribute is ContentProcessorAttribute)
                                {
                                    ContentProcessorAttribute processorAttribute = attribute as ContentProcessorAttribute;
                                    if (type.IsPublic)
                                        pipelineTypes.Add(type);
                                    if (processorAttribute.DisplayName != null)
                                    {
                                        processors.Add(type, processorAttribute);
                                    }
                                    break;
                                }
                            }
                        }
                        else
                        {
                            if (checkSerializable && type != null)
                            {
                                foreach (var attribute in type.GetCustomAttributes(true))
                                {
                                    if (attribute is SerializableAttribute)
                                    {
                                        SerializableTypes.Add(type);
                                        break;
                                    }
                                }
                            }
                            //try
                            //{
                            //}
                            //catch (Exception exception)
                            //{
                            //    exception.ToString();
                            //}
                        }
                    }
                }
            }
            PipelineTypes = pipelineTypes.ToArray();
        }

        /// <summary>
        /// 获取所有素材导入程序的特性。
        /// </summary>
        public static IEnumerable<ContentImporterAttribute> GetImporterAttributes()
        {
            return importers.Values;
        }

        /// <summary>
        /// 获取所有素材处理程序的特性。
        /// </summary>
        public static IEnumerable<ContentProcessorAttribute> GetProcessorAttributes()
        {
            return processors.Values;
        }
        
        /// <summary>
        /// 创建默认的素材导入程序的特性。
        /// </summary>
        public static ContentImporterAttribute GetDefaultImporterAttribute(string fileName)
        {
            string extension = Path.GetExtension(fileName).ToUpper();
            if (defaultImporters.ContainsKey(extension))
            {
                return defaultImporters[extension];
            }
            return null;
        }

        /// <summary>
        /// 创建默认的素材处理程序的特性。
        /// </summary>
        public static ContentProcessorAttribute GetDefaultProcessorAttribute(ContentImporterAttribute importerAttribute)
        {
            string defaultProcessor = importerAttribute.DefaultProcessor;
            if (defaultProcessor == "SpriteTextureProcessor")
                defaultProcessor = "TextureProcessor";
            foreach (var processor in processors.Keys)
            {
                if (processor.Name == defaultProcessor)
                {
                    return processors[processor];
                }
            }
            return null;
        }

        /// <summary>
        /// 创建素材导入程序。
        /// </summary>
        public static IContentImporter CreateImporter(ContentImporterAttribute importerAttribute)
        {
            foreach (var pair in importers)
            {
                if (pair.Value == importerAttribute)
                {
                    return Activator.CreateInstance(pair.Key) as IContentImporter;
                }
            }
            return null;
        }

        /// <summary>
        /// 创建素材处理程序。
        /// </summary>
        public static IContentProcessor CreateProcessor(ContentProcessorAttribute processorAttribute)
        {
            foreach (var pair in processors)
            {
                if (pair.Value == processorAttribute)
                {
                    return Activator.CreateInstance(pair.Key) as IContentProcessor;
                }
            }
            return null;
        }

        /// <summary>
        /// 获取素材导入程序的特性。
        /// </summary>
        public static ContentImporterAttribute GetImporterAttribute(IContentImporter importer)
        {
            Type type = importer.GetType();
            if (importers.ContainsKey(type))
            {
                return importers[type];
            }
            return null;
        }

        /// <summary>
        /// 获取素材处理程序的特性。
        /// </summary>
        public static ContentProcessorAttribute GetProcessorAttribute(IContentProcessor processor)
        {
            if (processor != null)
            {
                Type type = processor.GetType();
                if (processors.ContainsKey(type))
                {
                    return processors[type];
                }
            }
            return null;
        }

        #endregion
    }
}
